package com.huida.app.streamusage;

import com.huida.app.hutoolsusage.ArrayUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.junit.Test;
import org.springframework.test.context.event.annotation.AfterTestClass;
import sun.awt.im.CompositionArea;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wangzhuangzhuang
 * @DESC: Stream的filter与谓语逻辑
 * @date 2022-02-14 14:57
 */

@Data
@AllArgsConstructor
class Employee {
	private Integer id;
	private Integer age;
	private String gender;
	private String firstName;
	private String lastName;
}

@Slf4j
public class StreamUsageTestUnit {

	@Test
	public void test01() {
		Employee e1 = new Employee(1, 23, "M", "Rick", "Beethovan");
		Employee e2 = new Employee(2, 13, "F", "Martina", "Hengis");
		Employee e3 = new Employee(3, 43, "M", "Ricky", "Martin");
		Employee e4 = new Employee(4, 26, "M", "Jon", "Lowman");
		Employee e5 = new Employee(5, 19, "F", "Cristine", "Maria");
		Employee e6 = new Employee(6, 15, "M", "David", "Feezor");
		Employee e7 = new Employee(7, 68, "F", "Melissa", "Roy");
		Employee e8 = new Employee(8, 79, "M", "Alex", "Gussin");
		Employee e9 = new Employee(9, 15, "F", "Neetu", "Singh");
		Employee e10 = new Employee(10, 45, "M", "Naveen", "Jain");

		List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);

		List<Employee> filteredEmployees = employees.stream()
				.filter(e -> e.getAge() > 70 && e.getGender().equals("M"))
				.collect(Collectors.toList());
		// 15:02:38.984 [main] INFO com.huida.app.streamusage.FilterUsageTest - filteredEmployees: [Employee(id=8, age=79, gender=M, firstName=Alex, lastName=Gussin)]
		log.info("filteredEmployees: {}", filteredEmployees);
	}

	@Test
	public void test02() {
		List<String> alpha = Arrays.asList("Monkey", "Lion", "Giraffe", "Lemur");

		// 不使用Stream管道流
		List<String> alphaUpper = new ArrayList<>();
		for (String s : alpha) {
			alphaUpper.add(s.toUpperCase());
		}
		System.out.println(alphaUpper);

		// 使用Stream管道流
		List<String> collect = alpha.stream().map(String::toUpperCase).collect(Collectors.toList());
		System.out.println(alphaUpper);

		//[MONKEY, LION, GIRAFFE, LEMUR]
		//[MONKEY, LION, GIRAFFE, LEMUR]
	}

	// 处理非字符串类型集合元素
	// map()函数不仅可以处理数据还可以转换数据的类型
	@Test
	public void test03() {
		List<String> alpha = Arrays.asList("Monkey", "Lion", "Giraffe", "Lemur");
		List<Integer> lengths = alpha.stream()
				.map(String::length)
				.collect(Collectors.toList());
		// 15:33:04.114 [main] INFO com.huida.app.streamusage.StreamUsageTestUnit - lengths: [6, 4, 7, 5]
		log.info("lengths: " + ArrayUtils.toString(lengths));
	}

	// 处理对象数据格式转换
	// 10个Employees类对象
	// 需求： 1. 每一个Employee的年龄增加1岁
	// 2. 将性别中的"M"换成"Male", F换成“Female”
	@Test
	public void test04() {
		Employee e1 = new Employee(1, 23, "M", "Rick", "Beethovan");
		Employee e2 = new Employee(2, 13, "F", "Martina", "Hengis");
		Employee e3 = new Employee(3, 43, "M", "Ricky", "Martin");
		Employee e4 = new Employee(4, 26, "M", "Jon", "Lowman");
		Employee e5 = new Employee(5, 19, "F", "Cristine", "Maria");
		Employee e6 = new Employee(6, 15, "M", "David", "Feezor");
		Employee e7 = new Employee(7, 68, "F", "Melissa", "Roy");
		Employee e8 = new Employee(8, 79, "M", "Alex", "Gussin");
		Employee e9 = new Employee(9, 15, "F", "Neetu", "Singh");
		Employee e10 = new Employee(10, 45, "M", "Naveen", "Jain");

		List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);

		// map - style
		List<Employee> mappedEmp01 = employees.stream()
				.map(e -> {
					e.setAge(e.getAge() + 1);
					e.setGender(e.getGender().equals("M") ? "male" : "female");
					return e;
				}).collect(Collectors.toList());
		log.info("mappedEmp01: {}", ArrayUtils.toString(mappedEmp01));

		// peek - style
		List<Employee> mappedEmp02 = employees.stream()
				.peek(e -> {
					e.setAge(e.getAge() + 1);
					e.setGender(e.getGender().equals("M") ? "male" : "female");
				}).collect(Collectors.toList());
		log.info("mappedEmp02: {}", ArrayUtils.toString(mappedEmp02));
		/**
		 * map的参数e就是返回值，可以用peek函数，peek函数是一种特殊的map函数
		 * 当函数没有返回值或参数就是返回值的时候就可以使用peek函数
		 * */
	}

	/**
	 * map可以对管道流中的数据进行操作
	 * 但是如果管道中还有管道该如何处理？
	 * 即： 如果处理二维数组以及二维集合类。
	 * 实现一个简单需求： 将"hello", "world"两个字符串组成的集合
	 * 元素的每一个字母打印处理
	 * 写2层for循环
	 * 第一层：遍历字符串 - 将字符串拆分成char数组
	 *
	 * 第二层：for循环遍历char数组
	 * */
	@Test
	public void test05() {
		List<String> words = Arrays.asList("hello", "word");
		words.stream()
				.map(w -> Arrays.stream(w.split("")))  //[[h,e,l,l,o],[w,o,r,l,d]]
				.forEach(System.out::println);
//		java.util.stream.ReferencePipeline$Head@6b2fad11
//		java.util.stream.ReferencePipeline$Head@79698539

		// ★ 用map方法做不到的，这个需要用map方法无法实现。
		// map只能针对一维数组进行操作，数组里面还有数组，管道里面还有管道，它是处理不了每一个元素的
		words.stream()
				.flatMap(w -> Arrays.stream(w.split("")))
				.forEach(System.out::println);
//		h
//		e
//		l
//		l
//		o
//		w
//		o
//		r
//		d
	}


	// Distinct元素去重
	// 使用distinct方法对管道中的元素去重
	// 设计去重就涉及到元素之间的比较
	// distinct方法时调用Object的equals()方法进行对象比较
	// 当然也可以自定义equals方法下的比较规则
	@Test
	public void test06() {
		List<String>  uniqueAnimals = Stream.of("Monkey", "Monkey", "Lion", "Giraffe", "Lemur", "Lemur", "Lion")
				.distinct()
				.collect(Collectors.toList());
		// 16:19:17.631 [main] INFO com.huida.app.streamusage.StreamUsageTestUnit - uniqueAnimals: [Monkey, Lion, Giraffe, Lemur]
		log.info("uniqueAnimals: {}", ArrayUtils.toString(uniqueAnimals));
	}

	@Test
	public void test07(){
		Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
				.parallel()
				.forEach(System.out::println);
		/*
		* Giraffe
		* Lemur
		* Lion
		* Lion
		* Monkey
		* */
	}



	/**
	 * 如何对一个Employee对象组成的List集合进行排序
	 * 先按照性别字段倒序排序，再按照年龄的倒序进行排序
	 * SELECT *
	 * FROM employee
	 * ORDER BY gender DESC, age DESC;
	 * */
	@Test
	public void test8(){
		List<String> cities = Arrays.asList(
			"Milan", "London", "San Francisco",
			"Tokyo", "New Delhi"
		);
		// cities: [Milan, London, San Francisco, Tokyo, New Delhi]
		log.info("cities: {}", cities);

		cities.sort(String.CASE_INSENSITIVE_ORDER);
		// cities WITH CASE INSENSITIVE: [London, Milan, New Delhi, San Francisco, Tokyo]
		log.info("cities WITH CASE INSENSITIVE: {}", cities);

		cities.sort(Comparator.naturalOrder());
		// cities WITH NATURAL ORDER: [London, Milan, New Delhi, San Francisco, Tokyo]
		log.info("cities WITH NATURAL ORDER: {}", cities);
	}

	@Test
	public void test9(){
		List<Integer> numbers = Arrays.asList(6, 2, 1, 4, 9);
		log.info("numbers with original-order: {}", numbers);

		numbers.sort(Comparator.naturalOrder()); // 自然排序
		log.info("numbers with natural-order: {}", numbers);

		numbers.sort(Comparator.reverseOrder()); // 倒序排序
		log.info("numbers with reversed-order: {}", numbers);

//		numbers with original-order: [6, 2, 1, 4, 9]
//		numbers with natural-order: [1, 2, 4, 6, 9]
//		numbers with reversed-order: [9, 6, 4, 2, 1]
	}


	@Test
	public void test10() {

		Employee e1 = new Employee(1, 23, "M", "Rick", "Beethovan");
		Employee e2 = new Employee(2, 13, "F", "Martina", "Hengis");
		Employee e3 = new Employee(3, 43, "M", "Ricky", "Martin");
		Employee e4 = new Employee(4, 26, "M", "Jon", "Lowman");
		Employee e5 = new Employee(5, 19, "F", "Cristine", "Maria");
		Employee e6 = new Employee(6, 15, "M", "David", "Feezor");
		Employee e7 = new Employee(7, 68, "F", "Melissa", "Roy");
		Employee e8 = new Employee(8, 79, "M", "Alex", "Gussin");
		Employee e9 = new Employee(9, 15, "F", "Neetu", "Singh");
		Employee e10 = new Employee(10, 45, "M", "Naveen", "Jain");

		List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);

		// 正序
		employees.sort(Comparator.comparing(Employee::getAge));

		// 倒序
		employees.sort(Comparator.comparing(Employee::getAge).reversed());

		// 按性别的倒序排序，再按照年龄的倒序排序。
		employees.sort(
				Comparator.comparing(Employee::getGender)
						.thenComparing(Employee::getAge)
						.reversed()
		);

	}

}